En este link encontraréis los datos de un libro de recetas en formato zip. La tarea consiste en buscar reglas de asociación a partir de estos datos. ¿Es posible encontrar una regla para todas las recetas de pescado? ¿O de recetas picantes? Jugar con los datos, intenta encontrar alguna regla “interesante”.
Una vez se han limpiado los datos desde el documento “Limpieza_Recetas.Rmd”, los cargamos en forma de transacción con la función read.transactions.
recetas <- read.transactions("recipe_ingredients_transactions.csv", header = FALSE, rm.duplicates = FALSE, sep = ";")
Veamos como son los dos primeros elementos delconjunto de transacciones.
inspect(recetas[1:2])
## items
## [1] {apples,
## dill pickles,
## lemons,
## oranges,
## saladitos}
## [2] {basil,
## cloves garlic,
## corn,
## favorite seasonings,
## hamburger,
## italian seasoning,
## kidney beans,
## mild,
## mushrooms,
## onion,
## pepper,
## red pepper,
## tomato sauce,
## uncooked pasta}
Observemos cuales son los itemsets más frecuentes con un soporte de \(0.12\).
frequentItems <- eclat(recetas, parameter = list(support = 0.13))
## Eclat
##
## parameter specification:
## tidLists support minlen maxlen target ext
## FALSE 0.13 1 10 frequent itemsets TRUE
##
## algorithmic control:
## sparse sort verbose
## 7 -2 TRUE
##
## Absolute minimum support count: 193
##
## create itemset ...
## set transactions ...[4014 item(s), 1489 transaction(s)] done [0.01s].
## sorting and recoding items ... [6 item(s)] done [0.00s].
## creating bit matrix ... [6 row(s), 1489 column(s)] done [0.00s].
## writing ... [6 set(s)] done [0.00s].
## Creating S4 object ... done [0.00s].
inspect(frequentItems)
## items support transIdenticalToItemsets count
## [1] {salt} 0.3868368 576 576
## [2] {sugar} 0.2558764 381 381
## [3] {butter} 0.2014775 300 300
## [4] {water} 0.1927468 287 287
## [5] {flour} 0.1450638 216 216
## [6] {milk} 0.1383479 206 206
Vemos que el itemset salt es el que mayor soporte tiene. Observemos gáficamente los 15 itemsets más frecuentes.
itemFrequencyPlot(recetas, topN = 15, type="absolute", main="Top 15 Itemset más frecuentes")
Como hemos dicho antes, el itemset salt es el más frecuente. Es seguido por los itemsets sugar y water. Intentemos ahora determinar reglas de asociación para las recetas de pescado. Para ello haremos una lista con nombres de pescados para seleecionar aquellas que los contengan.
Seleccionaremos los siguientes pescados: “hake”, “shark”, “monkfish”, “rooster”, “cod”, “turbot”, “sole fish”, “fish”, “bass”, “anchovy”, “sardine”, “salmon”, “mackerel”, “herring”, “tuna”, “golden fish”, “trout”, “sea bream”, “seafood”, “snapper”, “bluefish”, “croaker”, “flounder”.
Tambien limpiaremos el conjunto de datos para el proximo apartado de las recetas picantes. Aqui seleccionaremos las palabras “red-hot”, “spicy”, “hot”, “peppery”, “racy”, “piquancy”.
Lo que haremos será al final guardar en dos documentos diferentes las recetas de pescados y las recetas picantes.
lista_pescados <- "hake|shark|monkfish|rooster|cod|turbot|sole fish|fish|bass|anchovy|sardine|salmon|mackerel|herring|tuna|golden fish|trout|sea bream|seafood|snapper|bluefish|croaker|flounder"
lista_picantes <- "red-hot|spicy|hot|peppery|racy|piquancy"
transformacion <- as(recetas, "data.frame") #Pasamos a data frame para la limpieza
transformacion$items <- as.character(transformacion$items) #Convertimos en caracter
transformacion$items <- substr(transformacion$items, 2, nchar(transformacion$items)-1) #Eliminamos las llaves que han aparecido
#### Para los pescados
pescados <- filter(transformacion, str_detect(items,lista_pescados)) #Buscamos los nombres de pescados en los ingredientes
pescados <- str_split_fixed(pescados$items, ",", n=Inf) #Separamos los ingredientes en columnas
for (i in 1:nrow(pescados)) { #Cambiamos los elementos vacios por NA
for (j in 1:ncol(pescados)) {
if (pescados[i,j] == "" ) {
pescados[i,j] = NA
}
}
}
write.csv(pescados, file = "recetas_pescados.csv", row.names = FALSE, col.names = FALSE) #Guardamos el resultado en un documento .csv
#### Para las picantes
nombres_recetas <- read.csv2("nombres_recetas.csv", header = FALSE) #Cargamos el nombre de las recetas
indices <- which(str_detect(nombres_recetas[,1],lista_picantes)) #Buscamos las que tengas palabras que indiquen comida picante
picantes <- transformacion[indices, ] #Seleccionamos los ingredientes de las recetas picantes
picantes <- str_split_fixed(picantes, ",", n=Inf) #Separamos los ingredientes en columnas
for (i in 1:nrow(picantes)) { #Cambiamos los elementos vacios por NA
for (j in 1:ncol(picantes)) {
if (picantes[i,j] == "" ) {
picantes[i,j] = NA
}
}
}
write.csv(picantes, file = "recetas_picantes.csv", row.names = FALSE, col.names = FALSE) #Guardamos el resultado en un documento .csv
Cargamos el conjunto de datos de las recetas de pescados.
recetas_pescados <- read.transactions("recetas_pescados.csv", sep = ",", skip = 1, rm.duplicates = FALSE)
## Warning in asMethod(object): removing duplicated items in transactions
inspect(recetas_pescados[1:2])
## items
## [1] {best foods mayonnaise,
## carrots,
## celery,
## frozen peas,
## hard boiled eggs,
## macaroni,
## maui onion,
## milk,
## salad potatoes,
## salt pepper,
## tuna}
## [2] {breadcrumbs,
## butter,
## fish steaks,
## milk,
## salt,
## sliced lemon,
## watercress}
Una vez tenemos solo las recetas que contienen pescado, vamos a ver cuales son los itemsets más frecuentes en ellas.
itemFrequencyPlot(recetas_pescados, topN = 15, type="absolute", main="Top 15 Itemset más frecuentes")
Los itemsets más frecuentes son la sal, la matequilla y la cebolla.
Pasamos a buscar reglas de asociación para las recetas de pescados. Consideraremos las reglas con antecedente vacío ya que corresponden a que un ingrediente es pescado.
Grules_pescado <- apriori(recetas_pescados, parameter = list(supp = 0.05, conf = 0.1, minlen=1), control = list (verbose=F))
Grules_conf_pescado <- sort (Grules_pescado, by="support", decreasing=TRUE)
inspect(Grules_conf_pescado)
## lhs rhs support confidence coverage
## [1] {} => {salt} 0.28333333 0.2833333 1.00000000
## [2] {} => {butter} 0.23333333 0.2333333 1.00000000
## [3] {} => {onion} 0.18333333 0.1833333 1.00000000
## [4] {} => {water} 0.16666667 0.1666667 1.00000000
## [5] {} => {lemon juice} 0.15000000 0.1500000 1.00000000
## [6] {} => {milk} 0.11666667 0.1166667 1.00000000
## [7] {} => {white wine} 0.11666667 0.1166667 1.00000000
## [8] {} => {olive} 0.11666667 0.1166667 1.00000000
## [9] {onion} => {salt} 0.11666667 0.6363636 0.18333333
## [10] {salt} => {onion} 0.11666667 0.4117647 0.28333333
## [11] {} => {flour} 0.10000000 0.1000000 1.00000000
## [12] {butter} => {salt} 0.10000000 0.4285714 0.23333333
## [13] {salt} => {butter} 0.10000000 0.3529412 0.28333333
## [14] {lemon juice} => {salt} 0.08333333 0.5555556 0.15000000
## [15] {salt} => {lemon juice} 0.08333333 0.2941176 0.28333333
## [16] {water} => {onion} 0.08333333 0.5000000 0.16666667
## [17] {onion} => {water} 0.08333333 0.4545455 0.18333333
## [18] {water} => {salt} 0.08333333 0.5000000 0.16666667
## [19] {salt} => {water} 0.08333333 0.2941176 0.28333333
## [20] {flour} => {butter} 0.06666667 0.6666667 0.10000000
## [21] {butter} => {flour} 0.06666667 0.2857143 0.23333333
## [22] {lime juice} => {fish sauce} 0.05000000 1.0000000 0.05000000
## [23] {fish sauce} => {lime juice} 0.05000000 0.6000000 0.08333333
## [24] {tuna} => {milk} 0.05000000 0.6000000 0.08333333
## [25] {milk} => {tuna} 0.05000000 0.4285714 0.11666667
## [26] {pepper} => {salt} 0.05000000 0.6000000 0.08333333
## [27] {salt} => {pepper} 0.05000000 0.1764706 0.28333333
## [28] {leaf} => {butter} 0.05000000 1.0000000 0.05000000
## [29] {butter} => {leaf} 0.05000000 0.2142857 0.23333333
## [30] {sugar} => {fish sauce} 0.05000000 0.6000000 0.08333333
## [31] {fish sauce} => {sugar} 0.05000000 0.6000000 0.08333333
## [32] {cayenne pepper} => {salt} 0.05000000 0.7500000 0.06666667
## [33] {salt} => {cayenne pepper} 0.05000000 0.1764706 0.28333333
## [34] {fish stock} => {butter} 0.05000000 0.7500000 0.06666667
## [35] {butter} => {fish stock} 0.05000000 0.2142857 0.23333333
## [36] {fish stock} => {salt} 0.05000000 0.7500000 0.06666667
## [37] {salt} => {fish stock} 0.05000000 0.1764706 0.28333333
## [38] {milk} => {butter} 0.05000000 0.4285714 0.11666667
## [39] {butter} => {milk} 0.05000000 0.2142857 0.23333333
## [40] {parsley} => {flour} 0.05000000 0.7500000 0.06666667
## [41] {flour} => {parsley} 0.05000000 0.5000000 0.10000000
## [42] {white wine} => {butter} 0.05000000 0.4285714 0.11666667
## [43] {butter} => {white wine} 0.05000000 0.2142857 0.23333333
## [44] {white wine} => {salt} 0.05000000 0.4285714 0.11666667
## [45] {salt} => {white wine} 0.05000000 0.1764706 0.28333333
## [46] {lemon juice} => {onion} 0.05000000 0.3333333 0.15000000
## [47] {onion} => {lemon juice} 0.05000000 0.2727273 0.18333333
## [48] {lemon juice} => {butter} 0.05000000 0.3333333 0.15000000
## [49] {butter} => {lemon juice} 0.05000000 0.2142857 0.23333333
## [50] {flour} => {water} 0.05000000 0.5000000 0.10000000
## [51] {water} => {flour} 0.05000000 0.3000000 0.16666667
## [52] {flour} => {salt} 0.05000000 0.5000000 0.10000000
## [53] {salt} => {flour} 0.05000000 0.1764706 0.28333333
## [54] {olive} => {salt} 0.05000000 0.4285714 0.11666667
## [55] {salt} => {olive} 0.05000000 0.1764706 0.28333333
## [56] {onion} => {butter} 0.05000000 0.2727273 0.18333333
## [57] {butter} => {onion} 0.05000000 0.2142857 0.23333333
## [58] {butter,flour} => {salt} 0.05000000 0.7500000 0.06666667
## [59] {flour,salt} => {butter} 0.05000000 1.0000000 0.05000000
## [60] {butter,salt} => {flour} 0.05000000 0.5000000 0.10000000
## [61] {onion,water} => {salt} 0.05000000 0.6000000 0.08333333
## [62] {salt,water} => {onion} 0.05000000 0.6000000 0.08333333
## [63] {onion,salt} => {water} 0.05000000 0.4285714 0.11666667
## lift count
## [1] 1.000000 17
## [2] 1.000000 14
## [3] 1.000000 11
## [4] 1.000000 10
## [5] 1.000000 9
## [6] 1.000000 7
## [7] 1.000000 7
## [8] 1.000000 7
## [9] 2.245989 7
## [10] 2.245989 7
## [11] 1.000000 6
## [12] 1.512605 6
## [13] 1.512605 6
## [14] 1.960784 5
## [15] 1.960784 5
## [16] 2.727273 5
## [17] 2.727273 5
## [18] 1.764706 5
## [19] 1.764706 5
## [20] 2.857143 4
## [21] 2.857143 4
## [22] 12.000000 3
## [23] 12.000000 3
## [24] 5.142857 3
## [25] 5.142857 3
## [26] 2.117647 3
## [27] 2.117647 3
## [28] 4.285714 3
## [29] 4.285714 3
## [30] 7.200000 3
## [31] 7.200000 3
## [32] 2.647059 3
## [33] 2.647059 3
## [34] 3.214286 3
## [35] 3.214286 3
## [36] 2.647059 3
## [37] 2.647059 3
## [38] 1.836735 3
## [39] 1.836735 3
## [40] 7.500000 3
## [41] 7.500000 3
## [42] 1.836735 3
## [43] 1.836735 3
## [44] 1.512605 3
## [45] 1.512605 3
## [46] 1.818182 3
## [47] 1.818182 3
## [48] 1.428571 3
## [49] 1.428571 3
## [50] 3.000000 3
## [51] 3.000000 3
## [52] 1.764706 3
## [53] 1.764706 3
## [54] 1.512605 3
## [55] 1.512605 3
## [56] 1.168831 3
## [57] 1.168831 3
## [58] 2.647059 3
## [59] 4.285714 3
## [60] 5.000000 3
## [61] 2.117647 3
## [62] 3.272727 3
## [63] 2.571429 3
Con un soporte mínimo de \(0.05\) y una confianza mínima de \(0.1\) hemos obtenido \(63\) reglas de asociación. Podemos observar que las primera reglas con mayor soporte son aquellas que el antecedente es vacío. Esto nos dice que las recetas de pescado llevan sal con un soporte de \(0.28333333\) y llevan mantequilla con un soporte igual al anterior.
La primera regla con antecedente no vacío y mayor soporte es:
\[ \mbox{(Si es una receta de pescado y lleva cebolla)} \rightarrow \ \mbox{(Lleva sal)} \]
Veamos estas reglas obtenidas pero ordenadas por mayor confianza.
Grules_conf_pescado <- sort (Grules_pescado, by="confidence", decreasing=TRUE)
inspect(Grules_conf_pescado)
## lhs rhs support confidence coverage
## [1] {lime juice} => {fish sauce} 0.05000000 1.0000000 0.05000000
## [2] {leaf} => {butter} 0.05000000 1.0000000 0.05000000
## [3] {flour,salt} => {butter} 0.05000000 1.0000000 0.05000000
## [4] {cayenne pepper} => {salt} 0.05000000 0.7500000 0.06666667
## [5] {fish stock} => {butter} 0.05000000 0.7500000 0.06666667
## [6] {fish stock} => {salt} 0.05000000 0.7500000 0.06666667
## [7] {parsley} => {flour} 0.05000000 0.7500000 0.06666667
## [8] {butter,flour} => {salt} 0.05000000 0.7500000 0.06666667
## [9] {flour} => {butter} 0.06666667 0.6666667 0.10000000
## [10] {onion} => {salt} 0.11666667 0.6363636 0.18333333
## [11] {fish sauce} => {lime juice} 0.05000000 0.6000000 0.08333333
## [12] {tuna} => {milk} 0.05000000 0.6000000 0.08333333
## [13] {pepper} => {salt} 0.05000000 0.6000000 0.08333333
## [14] {sugar} => {fish sauce} 0.05000000 0.6000000 0.08333333
## [15] {fish sauce} => {sugar} 0.05000000 0.6000000 0.08333333
## [16] {onion,water} => {salt} 0.05000000 0.6000000 0.08333333
## [17] {salt,water} => {onion} 0.05000000 0.6000000 0.08333333
## [18] {lemon juice} => {salt} 0.08333333 0.5555556 0.15000000
## [19] {flour} => {parsley} 0.05000000 0.5000000 0.10000000
## [20] {flour} => {water} 0.05000000 0.5000000 0.10000000
## [21] {flour} => {salt} 0.05000000 0.5000000 0.10000000
## [22] {water} => {onion} 0.08333333 0.5000000 0.16666667
## [23] {water} => {salt} 0.08333333 0.5000000 0.16666667
## [24] {butter,salt} => {flour} 0.05000000 0.5000000 0.10000000
## [25] {onion} => {water} 0.08333333 0.4545455 0.18333333
## [26] {milk} => {tuna} 0.05000000 0.4285714 0.11666667
## [27] {milk} => {butter} 0.05000000 0.4285714 0.11666667
## [28] {white wine} => {butter} 0.05000000 0.4285714 0.11666667
## [29] {white wine} => {salt} 0.05000000 0.4285714 0.11666667
## [30] {olive} => {salt} 0.05000000 0.4285714 0.11666667
## [31] {butter} => {salt} 0.10000000 0.4285714 0.23333333
## [32] {onion,salt} => {water} 0.05000000 0.4285714 0.11666667
## [33] {salt} => {onion} 0.11666667 0.4117647 0.28333333
## [34] {salt} => {butter} 0.10000000 0.3529412 0.28333333
## [35] {lemon juice} => {onion} 0.05000000 0.3333333 0.15000000
## [36] {lemon juice} => {butter} 0.05000000 0.3333333 0.15000000
## [37] {water} => {flour} 0.05000000 0.3000000 0.16666667
## [38] {salt} => {lemon juice} 0.08333333 0.2941176 0.28333333
## [39] {salt} => {water} 0.08333333 0.2941176 0.28333333
## [40] {butter} => {flour} 0.06666667 0.2857143 0.23333333
## [41] {} => {salt} 0.28333333 0.2833333 1.00000000
## [42] {onion} => {lemon juice} 0.05000000 0.2727273 0.18333333
## [43] {onion} => {butter} 0.05000000 0.2727273 0.18333333
## [44] {} => {butter} 0.23333333 0.2333333 1.00000000
## [45] {butter} => {leaf} 0.05000000 0.2142857 0.23333333
## [46] {butter} => {fish stock} 0.05000000 0.2142857 0.23333333
## [47] {butter} => {milk} 0.05000000 0.2142857 0.23333333
## [48] {butter} => {white wine} 0.05000000 0.2142857 0.23333333
## [49] {butter} => {lemon juice} 0.05000000 0.2142857 0.23333333
## [50] {butter} => {onion} 0.05000000 0.2142857 0.23333333
## [51] {} => {onion} 0.18333333 0.1833333 1.00000000
## [52] {salt} => {pepper} 0.05000000 0.1764706 0.28333333
## [53] {salt} => {cayenne pepper} 0.05000000 0.1764706 0.28333333
## [54] {salt} => {fish stock} 0.05000000 0.1764706 0.28333333
## [55] {salt} => {white wine} 0.05000000 0.1764706 0.28333333
## [56] {salt} => {flour} 0.05000000 0.1764706 0.28333333
## [57] {salt} => {olive} 0.05000000 0.1764706 0.28333333
## [58] {} => {water} 0.16666667 0.1666667 1.00000000
## [59] {} => {lemon juice} 0.15000000 0.1500000 1.00000000
## [60] {} => {milk} 0.11666667 0.1166667 1.00000000
## [61] {} => {white wine} 0.11666667 0.1166667 1.00000000
## [62] {} => {olive} 0.11666667 0.1166667 1.00000000
## [63] {} => {flour} 0.10000000 0.1000000 1.00000000
## lift count
## [1] 12.000000 3
## [2] 4.285714 3
## [3] 4.285714 3
## [4] 2.647059 3
## [5] 3.214286 3
## [6] 2.647059 3
## [7] 7.500000 3
## [8] 2.647059 3
## [9] 2.857143 4
## [10] 2.245989 7
## [11] 12.000000 3
## [12] 5.142857 3
## [13] 2.117647 3
## [14] 7.200000 3
## [15] 7.200000 3
## [16] 2.117647 3
## [17] 3.272727 3
## [18] 1.960784 5
## [19] 7.500000 3
## [20] 3.000000 3
## [21] 1.764706 3
## [22] 2.727273 5
## [23] 1.764706 5
## [24] 5.000000 3
## [25] 2.727273 5
## [26] 5.142857 3
## [27] 1.836735 3
## [28] 1.836735 3
## [29] 1.512605 3
## [30] 1.512605 3
## [31] 1.512605 6
## [32] 2.571429 3
## [33] 2.245989 7
## [34] 1.512605 6
## [35] 1.818182 3
## [36] 1.428571 3
## [37] 3.000000 3
## [38] 1.960784 5
## [39] 1.764706 5
## [40] 2.857143 4
## [41] 1.000000 17
## [42] 1.818182 3
## [43] 1.168831 3
## [44] 1.000000 14
## [45] 4.285714 3
## [46] 3.214286 3
## [47] 1.836735 3
## [48] 1.836735 3
## [49] 1.428571 3
## [50] 1.168831 3
## [51] 1.000000 11
## [52] 2.117647 3
## [53] 2.647059 3
## [54] 2.647059 3
## [55] 1.512605 3
## [56] 1.764706 3
## [57] 1.512605 3
## [58] 1.000000 10
## [59] 1.000000 9
## [60] 1.000000 7
## [61] 1.000000 7
## [62] 1.000000 7
## [63] 1.000000 6
Vemos que las reglas con confianza \(1\) son las siguientes:
\[ \mbox{(Si lleva zumo de limon)} \rightarrow \ \mbox{(Lleva salsa de pescado)} \\ \mbox{(Si lleva hojas)} \rightarrow \ \mbox{(Lleva mantequilla)} \\ \mbox{(Si lleva harina y sal)} \rightarrow \ \mbox{(Lleva mantequilla)} \]
Destacar de los resultados obtenidos que la sal aparece pocas veces siendo tan utilizada para cocinar.
Pasamos a estudiar las recetas que son picantes. Para ello cargamos el conjunto de datos que hemos creado anteriromente y que contiene solo recetas picantes.
recetas_picantes <- read.transactions("recetas_picantes.csv", sep = ",", skip = 1, rm.duplicates = FALSE)
## Warning in asMethod(object): removing duplicated items in transactions
inspect(recetas_picantes[1:2])
## items
## [1] {basil,
## cloves garlic,
## corn,
## favorite seasonings,
## hamburger,
## italian seasoning,
## kidney beans,
## mild,
## mushrooms,
## onion,
## pepper,
## tomato sauce,
## uncooked pasta}
## [2] {chicken breasts,
## chili,
## chopped celery,
## chopped cilantro,
## corn kernels,
## ground roasted peanuts,
## minced garlic,
## minced ginger root,
## pasta,
## peanut,
## rice vinegar,
## salt,
## sauce,
## seasame seeds,
## sesame,
## snow peas,
## sugar,
## water}
Veamos cuales son los itemsets más frecuentes en estas recetas.
itemFrequencyPlot(recetas_picantes, topN = 15, type="absolute", main="Top 15 Itemset más frecuentes")
Como en el caso anterior, el itemset más frecuente es la sal. Destacar que el segundo itemset más frecuente es el azúcar, que en un principio no parecería que tuviese mucha relación con el picante.
Pasamos a buscar reglas de asociación para las recetas picantes.
Grules_picantes <- apriori(recetas_picantes, parameter = list(supp = 0.05, conf = 0.1, minlen=2), control = list (verbose=F))
Grules_conf_picantes <- sort (Grules_picantes, by="support", decreasing=TRUE)
inspect(Grules_conf_picantes[1:30])
## lhs rhs support confidence
## [1] {sugar} => {water} 0.14285714 0.5714286
## [2] {water} => {sugar} 0.14285714 0.5714286
## [3] {vinegar} => {sugar} 0.10714286 0.7500000
## [4] {sugar} => {vinegar} 0.10714286 0.4285714
## [5] {sauce} => {sugar} 0.10714286 0.7500000
## [6] {sugar} => {sauce} 0.10714286 0.4285714
## [7] {sauce} => {water} 0.10714286 0.7500000
## [8] {water} => {sauce} 0.10714286 0.4285714
## [9] {minced garlic} => {water} 0.10714286 1.0000000
## [10] {water} => {minced garlic} 0.10714286 0.4285714
## [11] {vegetable} => {water} 0.10714286 0.6000000
## [12] {water} => {vegetable} 0.10714286 0.4285714
## [13] {sugar} => {salt} 0.10714286 0.4285714
## [14] {salt} => {sugar} 0.10714286 0.2727273
## [15] {water} => {salt} 0.10714286 0.4285714
## [16] {salt} => {water} 0.10714286 0.2727273
## [17] {sauce,sugar} => {water} 0.10714286 1.0000000
## [18] {sauce,water} => {sugar} 0.10714286 1.0000000
## [19] {sugar,water} => {sauce} 0.10714286 0.7500000
## [20] {flour} => {salt} 0.07142857 1.0000000
## [21] {salt} => {flour} 0.07142857 0.1818182
## [22] {cinnamon} => {vinegar} 0.07142857 1.0000000
## [23] {vinegar} => {cinnamon} 0.07142857 0.5000000
## [24] {cinnamon} => {sugar} 0.07142857 1.0000000
## [25] {sugar} => {cinnamon} 0.07142857 0.2857143
## [26] {cumin} => {garlic cloves} 0.07142857 1.0000000
## [27] {garlic cloves} => {cumin} 0.07142857 0.6666667
## [28] {lemon} => {salt} 0.07142857 1.0000000
## [29] {salt} => {lemon} 0.07142857 0.1818182
## [30] {freshly ground black pepper} => {salt} 0.07142857 1.0000000
## coverage lift count
## [1] 0.25000000 2.285714 4
## [2] 0.25000000 2.285714 4
## [3] 0.14285714 3.000000 3
## [4] 0.25000000 3.000000 3
## [5] 0.14285714 3.000000 3
## [6] 0.25000000 3.000000 3
## [7] 0.14285714 3.000000 3
## [8] 0.25000000 3.000000 3
## [9] 0.10714286 4.000000 3
## [10] 0.25000000 4.000000 3
## [11] 0.17857143 2.400000 3
## [12] 0.25000000 2.400000 3
## [13] 0.25000000 1.090909 3
## [14] 0.39285714 1.090909 3
## [15] 0.25000000 1.090909 3
## [16] 0.39285714 1.090909 3
## [17] 0.10714286 4.000000 3
## [18] 0.10714286 4.000000 3
## [19] 0.14285714 5.250000 3
## [20] 0.07142857 2.545455 2
## [21] 0.39285714 2.545455 2
## [22] 0.07142857 7.000000 2
## [23] 0.14285714 7.000000 2
## [24] 0.07142857 4.000000 2
## [25] 0.25000000 4.000000 2
## [26] 0.07142857 9.333333 2
## [27] 0.10714286 9.333333 2
## [28] 0.07142857 2.545455 2
## [29] 0.39285714 2.545455 2
## [30] 0.07142857 2.545455 2
Con un soporte mínimo de \(0.05\) y una confianza mínima de \(0.1\) hemos obtenido \(174\) reglas de asociación, aunque solo se muestran \(30\). Podemos observar que las reglas con mayor soporte son las siguientes:
\[ \mbox{(Si lleva azúcar)} \rightarrow \ \mbox{(Lleva agua)} \\ \mbox{(Si lleva agua)} \rightarrow \ \mbox{(Lleva azúcar)} \]
La primera regla con confianza \(1\) es la siguiente:
\[ \mbox{(Si lleva ajo molido)} \rightarrow \ \mbox{(Lleva agua)} \] Por último, veamos si podemos encontrar algúna regla interesante para todas la recetas que teníamos inicialmente.
Veamos cuales son los itemsets más frecuentes en estas recetas.
itemFrequencyPlot(recetas, topN = 15, type="absolute", main="Top 15 Itemset más frecuentes")
Los itemsets más frecuentes son la sal, el azúcar y el agua.
Pasamos a buscar reglas de asociación para todas las recetas.
Grules_todas_recetas <- apriori(recetas, parameter = list(supp = 0.05, conf = 0.1, minlen=2), control = list (verbose=F))
Grules_conf_todas_recetas <- sort (Grules_todas_recetas, by="confidence", decreasing=TRUE)
inspect(Grules_conf_todas_recetas)
## lhs rhs support confidence coverage
## [1] {pepper} => {salt} 0.06245803 0.7500000 0.08327737
## [2] {purpose flour} => {salt} 0.05305574 0.7452830 0.07118872
## [3] {baking powder} => {salt} 0.05104097 0.7102804 0.07186031
## [4] {vanilla} => {sugar} 0.05104097 0.6031746 0.08462055
## [5] {milk} => {salt} 0.07857623 0.5679612 0.13834788
## [6] {flour} => {salt} 0.08126259 0.5601852 0.14506380
## [7] {eggs} => {salt} 0.07253190 0.5595855 0.12961719
## [8] {eggs} => {sugar} 0.06380121 0.4922280 0.12961719
## [9] {sugar} => {salt} 0.12558764 0.4908136 0.25587643
## [10] {butter} => {salt} 0.09805238 0.4866667 0.20147750
## [11] {water} => {salt} 0.09066488 0.4703833 0.19274681
## [12] {flour} => {sugar} 0.06312962 0.4351852 0.14506380
## [13] {flour} => {butter} 0.06245803 0.4305556 0.14506380
## [14] {milk} => {butter} 0.05641370 0.4077670 0.13834788
## [15] {milk} => {sugar} 0.05439893 0.3932039 0.13834788
## [16] {water} => {sugar} 0.06380121 0.3310105 0.19274681
## [17] {salt} => {sugar} 0.12558764 0.3246528 0.38683680
## [18] {butter} => {sugar} 0.06514439 0.3233333 0.20147750
## [19] {butter} => {flour} 0.06245803 0.3100000 0.20147750
## [20] {butter} => {milk} 0.05641370 0.2800000 0.20147750
## [21] {sugar} => {butter} 0.06514439 0.2545932 0.25587643
## [22] {salt} => {butter} 0.09805238 0.2534722 0.38683680
## [23] {sugar} => {eggs} 0.06380121 0.2493438 0.25587643
## [24] {sugar} => {water} 0.06380121 0.2493438 0.25587643
## [25] {sugar} => {flour} 0.06312962 0.2467192 0.25587643
## [26] {salt} => {water} 0.09066488 0.2343750 0.38683680
## [27] {sugar} => {milk} 0.05439893 0.2125984 0.25587643
## [28] {salt} => {flour} 0.08126259 0.2100694 0.38683680
## [29] {salt} => {milk} 0.07857623 0.2031250 0.38683680
## [30] {sugar} => {vanilla} 0.05104097 0.1994751 0.25587643
## [31] {salt} => {eggs} 0.07253190 0.1875000 0.38683680
## [32] {salt} => {pepper} 0.06245803 0.1614583 0.38683680
## [33] {salt} => {purpose flour} 0.05305574 0.1371528 0.38683680
## [34] {salt} => {baking powder} 0.05104097 0.1319444 0.38683680
## lift count
## [1] 1.938802 93
## [2] 1.926608 79
## [3] 1.836124 76
## [4] 2.357289 76
## [5] 1.468219 117
## [6] 1.448118 121
## [7] 1.446567 108
## [8] 1.923694 95
## [9] 1.268787 187
## [10] 1.258067 146
## [11] 1.215973 135
## [12] 1.700763 94
## [13] 2.136991 93
## [14] 2.023883 84
## [15] 1.536694 81
## [16] 1.293634 95
## [17] 1.268787 187
## [18] 1.263631 97
## [19] 2.136991 93
## [20] 2.023883 84
## [21] 1.263631 97
## [22] 1.258067 146
## [23] 1.923694 95
## [24] 1.293634 95
## [25] 1.700763 94
## [26] 1.215973 135
## [27] 1.536694 81
## [28] 1.448118 121
## [29] 1.468219 117
## [30] 2.357289 76
## [31] 1.446567 108
## [32] 1.938802 93
## [33] 1.926608 79
## [34] 1.836124 76
Con un soporte mínimo de \(0.05\) y una confianza mínima de \(0.1\) hemos obtenido \(36\) reglas de asociación. Ignorando las reglas que contienen sal, tenemos que la primera regla con mayor confianza es la siguiente:
\[ \mbox{(Si lleva vainilla)} \rightarrow \ \mbox{(Lleva azúcar)} \]
En la UCI machine learning repository (en el siguiente link) encontraréis el dataset “Breast Cancer Wisconsin (Diagnostic) Data Set”. Realizar una detección de anomalías usando distintas técnicas.
Lo primero que haremos será cargar los datos.
datos_diagnostic <- read.csv("breast-cancer-wisconsin.data", header = FALSE)
dim(datos_diagnostic)
## [1] 699 11
Vemos que tenemos 699 datos y 11 variables, a las que renombraremos y seran las siguientes:
Id: Número de identificación
Espesor_Grupo: Variable numérica que indica el expesor del grupo (rango entre 1 y 10).
Uniform_tam_celula: Variable numérica que indica la uniformidad del tamaño de la célula (rango entre 1 y 10).
Uniform_forma_celula: Variable numérica que indica la uniformidad la forma de la célula (rango entre 1 y 10).
Adh_marginal: Variable numérica que indica la adhesión marginal (rango entre 1 y 10).
Tam_celula_epi: Variable numérica que indica el tamaño de una sola célula epitelial (rango entre 1 y 10).
Nuc_desnudos: Variable numérica que indica los núcleos desnudos (rango entre 1 y 10).
Cromatina: Variable numérica que indica la cromatina suave (rango entre 1 y 10).
Nucleolos: Variable numérica que indica los nucleolos normales (rango entre 1 y 10).
Mitosis: Variable numérica que indica la mitosis (rango entre 1 y 10).
Clase: Esta es la variable objetivo. Es una variable factor que con \(2\) indica que una célula es benigna y con \(4\) que una célula es maligna.
names(datos_diagnostic) <- c("Id", "Espesor_Grupo", "Uniform_tam_celula",
"Uniform_forma_celula", "Adh_marginal", "Tam_celula_epi",
"Nuc_desnudos", "Cromatina", "Nucleolos", "Mitosis", "Clase")
Veamos si este conjunto de datos contienen valores perdidos.
str(datos_diagnostic)
## 'data.frame': 699 obs. of 11 variables:
## $ Id : int 1000025 1002945 1015425 1016277 1017023 1017122 1018099 1018561 1033078 1033078 ...
## $ Espesor_Grupo : int 5 5 3 6 4 8 1 2 2 4 ...
## $ Uniform_tam_celula : int 1 4 1 8 1 10 1 1 1 2 ...
## $ Uniform_forma_celula: int 1 4 1 8 1 10 1 2 1 1 ...
## $ Adh_marginal : int 1 5 1 1 3 8 1 1 1 1 ...
## $ Tam_celula_epi : int 2 7 2 3 2 7 2 2 2 2 ...
## $ Nuc_desnudos : Factor w/ 11 levels "?","1","10","2",..: 2 3 4 6 2 3 3 2 2 2 ...
## $ Cromatina : int 3 3 3 3 3 9 3 3 1 2 ...
## $ Nucleolos : int 1 2 1 7 1 7 1 1 1 1 ...
## $ Mitosis : int 1 1 1 1 1 1 1 1 5 1 ...
## $ Clase : int 2 2 2 2 2 4 2 2 2 2 ...
Podemos observar que en la variable Nuc_desnudos existen valores perdidos. Veamos cuantos son.
nrow(filter(datos_diagnostic, Nuc_desnudos == "?"))
## [1] 16
Como no son muchos los valores peridos, lo que haremos será eliminarlos.
datos_diagnostic <- filter(datos_diagnostic, Nuc_desnudos != "?")
Lo que hemos de hacer ahora es pasar a numérico la variable Nuc_desnudos que se encontraba como factor y la variable Clase la pasaremos a factor.
datos_diagnostic$Nuc_desnudos <- as.numeric(datos_diagnostic$Nuc_desnudos)
datos_diagnostic$Clase <- as.factor(datos_diagnostic$Clase)
Comenzamos con la detección de anomalías eliminando la variable Id que no nos será de utilidad durante todo el estudio y la variable Clase que la utilizaremos al final.
datos_diagnostic_red <- datos_diagnostic[,-c(1, 11)]
Ya que todas las variables se encuentran en el mismo rango de valores observados, no escalaremos los datos.
Realizaremos ACP para reducir la dimensionalidad y poder dibujar los datos en el plano
datos_acp <- prcomp(datos_diagnostic_red)
summary(datos_acp)
## Importance of components:
## PC1 PC2 PC3 PC4 PC5 PC6 PC7
## Standard deviation 6.4365 2.10247 1.96247 1.76687 1.66825 1.59778 1.34319
## Proportion of Variance 0.6641 0.07086 0.06174 0.05004 0.04461 0.04092 0.02892
## Cumulative Proportion 0.6641 0.73498 0.79672 0.84677 0.89138 0.93230 0.96123
## PC8 PC9
## Standard deviation 1.26353 0.90676
## Proportion of Variance 0.02559 0.01318
## Cumulative Proportion 0.98682 1.00000
Hemos obtenido 6 componentes principales. Cada componente explica un porcentaje de la variación total del conjunto de datos. Ya que nuestra intención era disminuir la dimensionalidad para poder representar los datos, lo que haremos será seleccionar las 2 primeras componentes principales.
embedding <- data.table(datos_acp$x[, 1:2], Indices = c(1:nrow(datos_diagnostic_red)))
ggplot(embedding, aes(x = PC1, y = PC2)) +
geom_point(size = 10, colour = "steelblue", alpha = 0.3) +
geom_text(aes(label = Indices), check_overlap = TRUE) +
theme_minimal()
Aquí podemos observar lo que podrían ser posibles outliers (como pueden ser la observación 106 o la observación 441).
Pasamos a utilizar métodos para detectar estos outliers. El primero que utilizaremos será el método DBSCAN. Lo probaremos con diferentes parámetros. Los outliers son aquellos que se encuentran en el cluster 0.
2.2.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1 Revisar Parametros
dbscan(datos_diagnostic_red, eps = 5.5, minPts = 3)
## DBSCAN clustering for 683 objects.
## Parameters: eps = 5.5, minPts = 3
## The clustering contains 2 cluster(s) and 37 noise points.
##
## 0 1 2
## 37 643 3
##
## Available fields: cluster, eps, minPts
embedding[, DClusters_5.5_3 := dbscan(datos_diagnostic_red, eps = 5.5, minPts = 3)$cluster]
dbscan(datos_diagnostic_red, eps = 5, minPts = 3)
## DBSCAN clustering for 683 objects.
## Parameters: eps = 5, minPts = 3
## The clustering contains 2 cluster(s) and 68 noise points.
##
## 0 1 2
## 68 612 3
##
## Available fields: cluster, eps, minPts
embedding[, DClusters_5_3 := dbscan(datos_diagnostic_red, eps = 5, minPts = 3)$cluster]
dbscan(datos_diagnostic_red, eps = 5, minPts = 4)
## DBSCAN clustering for 683 objects.
## Parameters: eps = 5, minPts = 4
## The clustering contains 2 cluster(s) and 74 noise points.
##
## 0 1 2
## 74 606 3
##
## Available fields: cluster, eps, minPts
embedding[, DClusters_5_4 := dbscan(datos_diagnostic_red, eps = 5, minPts = 4)$cluster]
dbscan(datos_diagnostic_red, eps = 5.5, minPts = 4)
## DBSCAN clustering for 683 objects.
## Parameters: eps = 5.5, minPts = 4
## The clustering contains 2 cluster(s) and 43 noise points.
##
## 0 1 2
## 43 633 7
##
## Available fields: cluster, eps, minPts
embedding[, DClusters_5.5_4 := dbscan(datos_diagnostic_red, eps = 5.5, minPts = 4)$cluster]
dbscan(datos_diagnostic_red, eps = 6, minPts = 3)
## DBSCAN clustering for 683 objects.
## Parameters: eps = 6, minPts = 3
## The clustering contains 1 cluster(s) and 21 noise points.
##
## 0 1
## 21 662
##
## Available fields: cluster, eps, minPts
embedding[, DClusters_6_3 := dbscan(datos_diagnostic_red, eps = 6, minPts = 3)$cluster]
dbscan(datos_diagnostic_red, eps = 6, minPts = 4)
## DBSCAN clustering for 683 objects.
## Parameters: eps = 6, minPts = 4
## The clustering contains 1 cluster(s) and 23 noise points.
##
## 0 1
## 23 660
##
## Available fields: cluster, eps, minPts
embedding[, DClusters_6_4 := dbscan(datos_diagnostic_red, eps = 6, minPts = 4)$cluster]
dbscan(datos_diagnostic_red, eps = 6.5, minPts = 3)
## DBSCAN clustering for 683 objects.
## Parameters: eps = 6.5, minPts = 3
## The clustering contains 1 cluster(s) and 11 noise points.
##
## 0 1
## 11 672
##
## Available fields: cluster, eps, minPts
embedding[, DClusters_6.5_3 := dbscan(datos_diagnostic_red, eps = 6.5, minPts = 3)$cluster]
dbscan(datos_diagnostic_red, eps = 6.5, minPts = 4)
## DBSCAN clustering for 683 objects.
## Parameters: eps = 6.5, minPts = 4
## The clustering contains 1 cluster(s) and 11 noise points.
##
## 0 1
## 11 672
##
## Available fields: cluster, eps, minPts
embedding[, DClusters_6.5_4 := dbscan(datos_diagnostic_red, eps = 6.5, minPts = 4)$cluster]
dbscan(datos_diagnostic_red, eps = 6.5, minPts = 2)
## DBSCAN clustering for 683 objects.
## Parameters: eps = 6.5, minPts = 2
## The clustering contains 1 cluster(s) and 11 noise points.
##
## 0 1
## 11 672
##
## Available fields: cluster, eps, minPts
embedding[, DClusters_6.5_2 := dbscan(datos_diagnostic_red, eps = 6.5, minPts = 2)$cluster]
dbscan(datos_diagnostic_red, eps = 7, minPts = 3)
## DBSCAN clustering for 683 objects.
## Parameters: eps = 7, minPts = 3
## The clustering contains 1 cluster(s) and 4 noise points.
##
## 0 1
## 4 679
##
## Available fields: cluster, eps, minPts
embedding[, DClusters_7_3 := dbscan(datos_diagnostic_red, eps = 7, minPts = 3)$cluster]
dbscan(datos_diagnostic_red, eps = 7, minPts = 4)
## DBSCAN clustering for 683 objects.
## Parameters: eps = 7, minPts = 4
## The clustering contains 1 cluster(s) and 4 noise points.
##
## 0 1
## 4 679
##
## Available fields: cluster, eps, minPts
embedding[, DClusters_7_4 := dbscan(datos_diagnostic_red, eps = 7, minPts = 4)$cluster]
dbscan(datos_diagnostic_red, eps = 7, minPts = 2)
## DBSCAN clustering for 683 objects.
## Parameters: eps = 7, minPts = 2
## The clustering contains 1 cluster(s) and 4 noise points.
##
## 0 1
## 4 679
##
## Available fields: cluster, eps, minPts
embedding[, DClusters_7_2 := dbscan(datos_diagnostic_red, eps = 7, minPts = 2)$cluster]
Como podemos observar, dependiendo de los parámetros, podemos considerar 4, 11, 21, 23, 37, 43, 68 o 74 outliers. Veamos los diferentes casos representados gráficamente. El cluster con numeración 0 es el que representa los outliers.
ggplot(embedding, aes(x = PC1, y = PC2)) +
geom_point(aes(colour = factor(DClusters_7_4)), size = 10, alpha = 0.3) +
geom_text(aes(label = Indices), check_overlap = TRUE) +
theme_minimal() +
ggtitle("DBSCAN con eps=7 y minPts=4")+
labs(color="Clusters")
Vemos que los outliers se encuentran en el interior de las observaciones.
ggplot(embedding, aes(x = PC1, y = PC2)) +
geom_point(aes(colour = factor(DClusters_6.5_2)), size = 10, alpha = 0.3) +
geom_text(aes(label = Indices), check_overlap = TRUE) +
theme_minimal() +
ggtitle("DBSCAN con eps=6.5 y minPts=2")+
labs(color="Clusters")
A los anteriores outliers se han añadido otros como pueden ser el 99 o el 348.
ggplot(embedding, aes(x = PC1, y = PC2)) +
geom_point(aes(colour = factor(DClusters_6_3)), size = 10, alpha = 0.3) +
geom_text(aes(label = Indices), check_overlap = TRUE) +
theme_minimal() +
ggtitle("DBSCAN con eps=6 y minPts=3")+
labs(color="Clusters")
Vemos que se siguen añadiendo observaciones como outliers a los anteriores (como puede ser la observación 480) pero de momento no se podrían distiguir a simple vista sin el uso de las etiquetas.
ggplot(embedding, aes(x = PC1, y = PC2)) +
geom_point(aes(colour = factor(DClusters_6_4)), size = 10, alpha = 0.3) +
geom_text(aes(label = Indices), check_overlap = TRUE) +
theme_minimal() +
ggtitle("DBSCAN con eps=6 y minPts=4")+
labs(color="Clusters")
Se ha añadido a los anteriores outliers la observación 232.
ggplot(embedding, aes(x = PC1, y = PC2)) +
geom_point(aes(colour = factor(DClusters_5.5_3)), size = 10, alpha = 0.3) +
geom_text(aes(label = Indices), check_overlap = TRUE) +
theme_minimal() +
ggtitle("DBSCAN con eps=5.5 y minPts=3")+
labs(color="Clusters")
Vemos que aquí nos separa en dos clusters a parte del cluster de los outliers. El cluster con el número 2, se encuentra en la parte inferior del gráfico, al que pertenece la observación 61.
ggplot(embedding, aes(x = PC1, y = PC2)) +
geom_point(aes(colour = factor(DClusters_5.5_4)), size = 10, alpha = 0.3) +
geom_text(aes(label = Indices), check_overlap = TRUE) +
theme_minimal() +
ggtitle("DBSCAN con eps=5.5 y minPts=4")+
labs(color="Clusters")
En este caso, la observación 61 que antes no se consideraba outlier y generaba un cluster con otra observación, ahora se considera como outlier.
ggplot(embedding, aes(x = PC1, y = PC2)) +
geom_point(aes(colour = factor(DClusters_5_3)), size = 10, alpha = 0.3) +
geom_text(aes(label = Indices), check_overlap = TRUE) +
theme_minimal() +
ggtitle("DBSCAN con eps=5 y minPts=3")+
labs(color="Clusters")
Con estos parámetros, se ha añadido como outlier la observación 441 que es la que podíamos pensar que era un outlier a simple vista.
ggplot(embedding, aes(x = PC1, y = PC2)) +
geom_point(aes(colour = factor(DClusters_5_4)), size = 10, alpha = 0.3) +
geom_text(aes(label = Indices), check_overlap = TRUE) +
theme_minimal() +
ggtitle("DBSCAN con eps=5 y minPts=4")+
labs(color="Clusters")
Se añaden algunos outliers en la parte inferior a los anteriormentes considerados.
Pasamos a utilizar el método de Maximización de expectativas (Expectation Maximization). Lo probaremos con 3,4 y 6 clusters.
#Mclust
mclust <- Mclust(datos_diagnostic_red, G = 4)
embedding[, EMClusters_4 := mclust$classification]
mclust <- Mclust(datos_diagnostic_red, G = 3)
embedding[, EMClusters_3 := mclust$classification]
mclust <- Mclust(datos_diagnostic_red, G = 6)
embedding[, EMClusters_6 := mclust$classification]
Veamos gráficamente los resultados. Los outliers son aquellos que se encuentran en el cluster 1.
ggplot(embedding, aes(x = PC1, y = PC2)) +
geom_point(aes(colour = factor(EMClusters_4)), size = 10, alpha = 0.3) +
geom_text(aes(label = Indices), check_overlap = TRUE) +
theme_minimal()+
scale_color_manual(values=c("black", "turquoise1","green", "yellow"))+
ggtitle("EM con 4 clusters")+
labs(color="Clusters")
Los outliers considerados se encuentran a la derecha del gráfico, lo que parece poco coherente ya que ese gran grupo podría considerarse como un cluster.
ggplot(embedding, aes(x = PC1, y = PC2)) +
geom_point(aes(colour = factor(EMClusters_3)), size = 10, alpha = 0.3) +
geom_text(aes(label = Indices), check_overlap = TRUE) +
theme_minimal()+
ggtitle("EM con 3 clusters")+
labs(color="Clusters")
Igual que en el caso anterior, los outliers los selecciona de la parte deecha del gráfico.
ggplot(embedding, aes(x = PC1, y = PC2)) +
geom_point(aes(colour = factor(EMClusters_6)), size = 10, alpha = 0.3) +
geom_text(aes(label = Indices), check_overlap = TRUE) +
theme_minimal()+
scale_color_manual(values=c("black", "turquoise1","green", "yellow", "red", "orange"))+
ggtitle("EM con 6 clusters")+
labs(color="Clusters")
En este caso ocurre igual que con los anteriores utilizando el método EM.
Por último, utilizaremos el método LOF. Este método se basa en la densidad para detectar los outliers. Lo ejecutaremos con diferentes numeros de vecinos, que será de 3 a 8.
outlier.scores <- lof(datos_diagnostic_red, k=c(3:8))
Seleccionaremos las 10 observaciones que tengan un índice de outlier más grande en cada ejecución.
outliers = matrix(rep(0, 60), nrow =10 , ncol = 6)
for (i in 1:6) {
outliers[,i] <- order(outlier.scores[,i], decreasing=TRUE)[1:10]
}
outliers
## [,1] [,2] [,3] [,4] [,5] [,6]
## [1,] 7 7 7 3 1 1
## [2,] 8 8 8 7 3 3
## [3,] 10 10 9 8 7 7
## [4,] 20 20 10 9 8 8
## [5,] 26 26 20 10 9 9
## [6,] 33 33 30 20 10 10
## [7,] 34 34 33 26 11 11
## [8,] 44 44 34 30 26 12
## [9,] 68 68 44 33 30 26
## [10,] 78 78 60 34 33 28
Podemos ver que con este método, las observaciones 7, 8 y 10 son outliers en todos los casos.
Una vez que hemos aplicado varios métodos para detectar outliers, vamos a añadir las etiquetas y ver si de verdad pueden ser outliers o no.
data <- data.table(datos_acp$x[, 1:2], Indices = c(1:nrow(datos_diagnostic_red)), Clase = datos_diagnostic$Clase)
ggplot(data, aes(x = PC1, y = PC2)) +
geom_point(mapping = aes(color= Clase) ,size = 10, alpha = 0.3) +
geom_text(aes(label = Indices), check_overlap = TRUE) +
theme_minimal()
Aquí podemos ver representados los datos utilizando componentes principales donde el color representa la clase a la que pertenecen. Viendo esto y relacionandolo con los diferentes métodos empleados para detectar los outliers, se ha decidido escoger el método DBSCAN con parámetros eps=5 y minPts=3. Veamos gráficamente cuáles son los outliers que ha escogido este método utilizando el color para representar la clase a la que pertenecen.
embedding[, Clase := datos_diagnostic$Clase]
dbscan_outliers = which(embedding$DClusters_5_3==0)
ggplot(embedding[dbscan_outliers,], aes(x = PC1, y = PC2)) +
geom_point(mapping = aes(color= Clase) ,size = 10, alpha = 0.3) +
geom_text(aes(label = Indices), check_overlap = TRUE) +
theme_minimal()
Observamos que este método a escogido observaciones como la 441 o 106 que podrían considerarse outliers a simple vista, pero tambien ha recogido observaciones como la 420 o la 307 que no podrían verse como outliers pero que lo son si consideramos la clase a la que pertenecen. Es por esto que se ha escogido este método con respecto a los otros.